home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / osrc.arc / HS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-04-13  |  14.3 KB  |  595 lines

  1. /* Interface driver for the DRSI PCPA or the Eagle 8530 boards for the IBM PC
  2.  * connected to a WA4DSY 56kbps modem. Uses polling-loop transfers with
  3.  * interrupts disabled for maximum speed.
  4. */
  5. #include <stdio.h>
  6. #include "global.h"
  7. #include "mbuf.h"
  8. #include "iface.h"
  9. #include "hs.h"
  10. #include "8530.h"
  11. #include "ax25.h"
  12. #include "trace.h"
  13.  
  14. extern struct iface *Ifaces;
  15. extern struct mbuf *Hopper;
  16. int (*getirq())();    /* Getirq is a function returning a pointer to
  17.                  * a function returning int */
  18.  
  19. static void hexint(),hrxint(),htxint(),hdlcparam(),flushrx();
  20. static void hstxon(),hstxoff(),hs_tx();
  21. int rx8530();
  22.  
  23. struct hs Hs[NHS];
  24. int hs0vec();
  25. int (*Hshandle[])() = { hs0vec };
  26. static struct hdlc Hdlc[2*NHS];
  27. int16 Nhs;
  28.  
  29. /* Master interrupt handler for the PC-100 card. All interrupts come
  30.  * here first, then are switched out to the appropriate routine.
  31.  */
  32. hsint(dev)
  33. int16 dev;
  34. {
  35.     register char iv;
  36.     int16 hsbase;
  37.     register struct hdlc *hp;
  38.     
  39.     Hs[dev].ints++;
  40.     hsbase = Hs[dev].addr;
  41.  
  42. #ifdef    foo
  43.     outportb(hsbase+4,0x8+0x10);    /* HIT EAGLE INTACK */
  44.     (void)inportb(hsbase+CHANA+CTL,R0);
  45.     outportb(hsbase+4,0x8);        /***/
  46. #endif
  47.  
  48.     /* Read interrupt status from channel A */
  49.     while((iv = read_scc(hsbase+CHANA+CTL,R3)) != 0){
  50.         if(iv & CHARxIP){
  51.             /* Channel A Rcv Interrupt Pending */
  52.             hp = &Hdlc[2*dev];
  53.             hrxint(hp);
  54.         } else if(iv & CHATxIP){
  55.             /* Channel A Transmit Int Pending */
  56.             hp = &Hdlc[2*dev];
  57.             htxint(hp);
  58.         } else if(iv & CHAEXT){
  59.             /* Channel A External Status Int */
  60.             hp = &Hdlc[2*dev];
  61.             hexint(hp);
  62.         } else if(iv & CHBRxIP){
  63.             /* Channel B Rcv Interrupt Pending */
  64.             hp = &Hdlc[(2*dev)+1];
  65.             hrxint(hp);
  66.         } else if(iv & CHBTxIP){
  67.             /* Channel B Transmit Int Pending */
  68.             hp = &Hdlc[(2*dev)+1];
  69.             htxint(hp);
  70.         } else if(iv & CHBEXT){
  71.             /* Channel B External Status Int */
  72.             hp = &Hdlc[(2*dev)+1];
  73.             hexint(hp);
  74.         }
  75.         /* Reset interrupt pending state */
  76.         write_scc(hp->ctl,R0,RES_H_IUS);
  77.         outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  78.         outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  79.     }
  80.     outportb(hsbase+CHANA+CTL,0);    /* Restore pointer to 0 */
  81.     outportb(hsbase+CHANB+CTL,0);    /* Restore pointer to 0 */
  82. }
  83. /* HDLC SIO External/Status interrupts
  84.  * The only one that can happen in this driver is a DCD change
  85.  */
  86. static void
  87. hexint(hp)
  88. register struct hdlc *hp;
  89. {
  90.     struct mbuf *rcvbuf;
  91.     struct phdr *phdr;
  92.     char *cp;
  93.     int cnt,data;
  94.     register int ctl;
  95.  
  96.     ctl = hp->ctl;
  97.     data = hp->data;
  98.     hp->exints++;
  99.  
  100.     /* Allocate a receive buffer */
  101.     if((rcvbuf = alloc_mbuf(hp->bufsiz+sizeof(struct phdr))) == NULLBUF){
  102.         /* Alloc failed; refuse to proceed */
  103.         hp->nomem++;
  104.         write_scc(ctl,R0,RES_EXT_INT);
  105.         return;
  106.     }
  107.     /* Allow space for phdr descriptor on front */
  108.     cp = rcvbuf->data + sizeof(struct phdr);
  109.     cnt = 0;
  110.  
  111.     /* Disable DCDIE bit so we can track changes in DCD */
  112.     write_scc(ctl,R15,0);
  113.  
  114.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  115.     flushrx(data);
  116.     while((cnt = rx8530(ctl,data,cp,hp->bufsiz)) != -1){
  117.         if(cnt > 4){
  118.             /* Good frame */
  119.             hp->good++;
  120.             /* Toss crc */
  121.             rcvbuf->cnt = sizeof(struct phdr) + cnt - 1;
  122.             phdr = (struct phdr *)rcvbuf->data;
  123.             phdr->iface = hp->iface;
  124.             phdr->type = TYPE_AX25;
  125.             enqueue(&Hopper,rcvbuf);
  126.             /* Replenish buffer */
  127.             rcvbuf = alloc_mbuf(hp->bufsiz + sizeof(struct phdr));
  128.         }
  129.         /* Start new buffer */
  130.         if(rcvbuf == NULLBUF)
  131.             break;    /* alloc failed */
  132.         cp = rcvbuf->data + sizeof(struct phdr);
  133.         cnt = 0;
  134.     }    
  135.     write_scc(ctl,R0,RES_EXT_INT);
  136.     write_scc(ctl,R15,DCDIE);    /* Re-enable DCD */
  137.     write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  138.  
  139.     /* Get rid of fragmentary buffer */
  140.     free_p(rcvbuf);
  141. }
  142. static void
  143. flushrx(data)
  144. register int16 data;
  145. {
  146.     register int i = 5;
  147.     while(i-- != 0)
  148.         (void)inportb(data);
  149. }
  150. /* HDLC receiver interrupt handler.
  151.  * Not used in this driver
  152.  */
  153. static void
  154. hrxint(hp)
  155. register struct hdlc *hp;
  156. {
  157. }
  158. /* HDLC transmit interrupt service routine
  159.  * Not used in this driver
  160.  */
  161. static void
  162. htxint(hp)
  163. register struct hdlc *hp;
  164. {
  165. }
  166.  
  167. /* (re)Initialize HDLC controller parameters */
  168. static void
  169. hdlcparam(hp)
  170. register struct hdlc *hp;
  171. {
  172.     char i_state;
  173.     register int16 ctl;
  174.  
  175.     /* Initialize 8530 channel for SDLC operation */
  176.     ctl = hp->ctl;
  177.     i_state = dirps();
  178.  
  179. #ifdef    foo
  180.     switch(ctl & 2){
  181.     case CHANA:
  182.         write_scc(ctl,R9,CHRA);    /* Reset channel A */
  183.         break;
  184.     case CHANB:
  185.         write_scc(ctl,R9,CHRB);    /* Reset channel B */
  186.         break;
  187.     }
  188.     pause(1L);    /* Allow plenty of time for resetting */
  189. #endif
  190.  
  191.     /* Deselect interrupts for now */
  192.     write_scc(ctl,R1,0);
  193.     write_scc(ctl,R15,0);
  194.  
  195.     /* X1 clock, SDLC mode, Sync modes enable, parity disable */
  196.     write_scc(ctl,R4,X1CLK | SDLC | SYNC_ENAB);
  197.  
  198.     /* CRC preset 1, NRZ encoding, no active on poll, flag idle,
  199.      * flag on underrun, no loop mode, 8 bit sync
  200.      */
  201.     write_scc(ctl,R10,CRCPS|NRZ);
  202.  
  203.     /* 8530 gets both tx and rx clock from modem.
  204.      * TRxC = receive clock, RTxC = transmit clock
  205.      */
  206.     write_scc(ctl,R11,RCTRxCP | TCRTxCP);
  207.  
  208.     /* Note: baud rate generator not used */
  209.  
  210.     /* Null out SDLC start address */
  211.     write_scc(ctl,R6,0);
  212.  
  213.     /* SDLC flag */
  214.     write_scc(ctl,R7,FLAG);
  215.  
  216.     /* DTR On, 8 bit TX chars, no break, TX enable, SDLC CRC,
  217.      * RTS off, TxCRC enable
  218.      */
  219.     write_scc(ctl,R5,DTR|Tx8|TxENAB|TxCRC_ENAB);
  220.  
  221.     /* 8 bit RX chars, auto enables off, no hunt mode, RxCRC enable,
  222.      * no address search, no inhibit sync chars, disable RX. Rx is
  223.      * started only by an actual DCD interrupt
  224.      */
  225.     write_scc(ctl,R3,RxENABLE|RxCRC_ENAB|Rx8);
  226.  
  227.     /* Dummy interrupt vector
  228.      * (This probably isn't necessary)
  229.      */
  230.     write_scc(ctl,R2,0);
  231.  
  232.     /* Enable only the external interrupts (modem interrupts) since
  233.      * polling is used for all actual tx/rx operations
  234.      */
  235.     write_scc(ctl,R1,EXT_INT_ENAB);
  236.  
  237.     /* Enable only DCD interrupts */
  238.     write_scc(ctl,R15,DCDIE);
  239.  
  240.     /* No reset, status low, master int enable, enable lower chain,
  241.      * no vector
  242.      */
  243.     write_scc(ctl,R9,MIE|NV);
  244.  
  245.     restore(i_state);
  246. }
  247. /* Attach a high speed iterface to the system
  248.  * argv[0]: hardware type, must be "hs"
  249.  * argv[1]: I/O address, e.g., "0x380"
  250.  * argv[2]: vector, e.g., "2"
  251.  * argv[3]: mode, must be "ax25"
  252.  * argv[4]: interface label, e.g., "drsi0". 
  253.  * argv[5]: receiver packet buffer size in bytes
  254.  * argv[6]: maximum transmission unit, bytes
  255.  * argv[7]: keyup delay, clock ticks
  256.  * argv[8]: persistence value, 0-255
  257.  */
  258. int
  259. hs_attach(argc,argv)
  260. int argc;
  261. char *argv[];
  262. {
  263.     register struct iface *if_hsa,*if_hsb;
  264.     struct hdlc *hp;
  265.     int dev;
  266.  
  267.     if(Nhs >= NHS){
  268.         printf("Too many hs controllers\n");
  269.         return -1;
  270.     }
  271.     if(if_lookup(argv[4]) != NULLIF){
  272.         printf("Interface %s already exists\n",argv[4]);
  273.         return -1;
  274.     }
  275.     dev = Nhs++;
  276.  
  277.     /* Initialize hardware-level control structure */
  278.     Hs[dev].addr = htoi(argv[1]);
  279.     Hs[dev].vec = htoi(argv[2]);
  280.  
  281.     /* Save original interrupt vector */
  282.     Hs[dev].save.vec = getirq(Hs[dev].vec);
  283.     /* Set new interrupt vector */
  284.     if(setirq(Hs[dev].vec,Hshandle[dev]) == -1){
  285.         printf("IRQ %u out of range\n",Hs[dev].vec);
  286.         Nhs--;
  287.         return -1;
  288.     }
  289.     /* Create interface structures and fill in details */
  290.     if_hsa = (struct iface *)calloc(1,sizeof(struct iface));
  291.     if_hsb = (struct iface *)calloc(1,sizeof(struct iface));
  292.  
  293.     if_hsa->name = strdup(argv[4]);
  294.     if_hsb->name = strdup(argv[4]);
  295.     if_hsb->name[strlen(argv[4]) - 1]++;    /* kludge */
  296.     if_hsb->mtu = if_hsa->mtu = atoi(argv[6]);
  297.     if_hsa->dev = 2*dev;
  298.     if_hsb->dev = 2*dev + 1;
  299.     if_hsb->stop = if_hsa->stop = hs_stop;
  300.     if_hsb->output = if_hsa->output = ax_output;
  301.     if_hsb->raw = hs_raw;
  302.  
  303.     if(strcmp(argv[3],"ax25") == 0){
  304.         axarp();
  305.         if(Mycall.call[0] == '\0'){
  306.             printf("set mycall first\n");
  307.             free((char *)if_hsa);
  308.             free((char *)if_hsb);
  309.             return -1;
  310.         }        
  311.         if_hsb->send = if_hsa->send = ax_send;
  312.         if(if_hsb->hwaddr == NULLCHAR)
  313.             if_hsb->hwaddr = malloc(sizeof(Mycall));
  314.         memcpy(if_hsb->hwaddr,(char *)&Mycall,sizeof(Mycall));
  315.     } else {
  316.         printf("Mode %s unknown for interface %s\n",
  317.             argv[3],argv[4]);
  318.         free((char *)if_hsa);
  319.         free((char *)if_hsb);
  320.         return -1;
  321.     }
  322.     if_hsa->next = if_hsb;
  323.     if_hsb->next = Ifaces;
  324.     Ifaces = if_hsa;
  325.  
  326.     write_scc(Hs[dev].addr+CHANA+CTL,R9,FHWRES);
  327.     hp = &Hdlc[2*dev+1];
  328.     hp->ctl = Hs[dev].addr + CHANB + CTL;
  329.     hp->data = Hs[dev].addr + CHANB + DATA;
  330.     hp->bufsiz = atoi(argv[5]);
  331.     if(argc > 7)
  332.         hp->txdelay = atol(argv[7]);
  333.     else
  334.         hp->txdelay = 1L;
  335.     if(argc > 8)
  336.         hp->p = atoi(argv[8]);
  337.     else
  338.         hp->p = 64;
  339.     hp->iface = if_hsb;
  340.     hdlcparam(hp);
  341.     newproc("hs_tx",1024,hs_tx,0,hp,NULL);
  342.  
  343.     hp = &Hdlc[2*dev];
  344.     hp->ctl = Hs[dev].addr + CHANA + CTL;
  345.     hp->data = Hs[dev].addr + CHANA + DATA;
  346.     hp->bufsiz = atoi(argv[5]);
  347.     hp->txdelay = Hdlc[2*dev+1].txdelay;
  348.     hp->p = Hdlc[2*dev+1].p;
  349.     hp->iface = if_hsb;
  350.     hp->iface = if_hsa;
  351.     hdlcparam(hp);
  352.     newproc("hs_tx",1024,hs_tx,0,hp,NULL);
  353.  
  354.     outportb(Hs[dev].addr + 4,0x08);    /*EAGLE INT GATE */
  355.     /* Clear mask (enable interrupt) in 8259 interrupt controller */
  356.     maskon(Hs[dev].vec);
  357.  
  358.     return 0;
  359. }
  360. int
  361. hs_stop(iface)
  362. struct iface *iface;
  363. {
  364.     int16 dev;
  365.  
  366.     dev = iface->dev;
  367.     if(dev & 1)
  368.         return -1;    /* Valid only for the first device */
  369.     dev >>= 1;    /* Convert back into hs number */
  370.     /* Turn off interrupts */
  371.     maskoff(Hs[dev].vec);
  372.  
  373.     /* Restore original interrupt vector */
  374.     setirq(Hs[dev].vec,Hs[dev].save.vec);
  375.  
  376.     /* Force hardware reset */
  377.     write_scc(Hs[dev].addr + CHANA+CTL,R9,FHWRES);
  378.     return 0;
  379. }
  380. /* Send raw packet */
  381. int
  382. hs_raw(iface,bp)
  383. struct iface *iface;
  384. struct mbuf *bp;
  385. {
  386.  
  387.     struct hdlc *hp;
  388.  
  389.     dump(iface,IF_TRACE_OUT,TYPE_AX25,bp);
  390.     hp = &Hdlc[iface->dev];
  391.     hp->txpkts++;
  392.     enqueue(&hp->txq,bp);    /* Put on queue for hs_tx process */
  393.     return 0;
  394. }
  395.  
  396. /* High speed transmit process */
  397. void
  398. hs_tx(unused,hp,a)
  399. int unused;
  400. struct hdlc *hp;
  401. void *a;    /* Unused */
  402. {
  403.     struct mbuf *bp;
  404.     register int16 cnt;
  405.     register char *cp;
  406.     char *buffer;
  407.     int16 ctl,data;
  408.     int txon = 0;    /* Transmitter on/off state */
  409.  
  410.     ctl = hp->ctl;
  411.     data = hp->data;
  412.  
  413.     for(;;){
  414.         /* Wait for work */
  415.         while(hp->txq == NULLBUF){
  416.             if(txon){
  417.                 /* No more frames, shut down tx */
  418.                 hstxoff(hp);
  419.                 txon = 0;
  420.             }
  421.             pwait(&hp->txq);
  422.         }
  423.         bp = dequeue(&hp->txq);
  424.         /* Copy to new buffer for speed */
  425.         cnt = len_mbuf(bp);
  426.         if((cp = buffer = malloc(cnt)) == NULLCHAR){
  427.             hp->nomem++;
  428.             free_p(bp);
  429.             continue;
  430.         }
  431.         pullup(&bp,cp,cnt);
  432.         /* Turn transmitter on if necessary */
  433.         if(!txon){
  434.             hstxon(hp);
  435.             txon = 1;
  436.         }
  437.         /* Initialize transmitter CRC */
  438.         write_scc(ctl,R0,RES_Tx_CRC);
  439.         for(;;){
  440.             /* Wait for the transmitter to become ready */
  441.             while(!(inportb(ctl) & Tx_BUF_EMP))
  442.                 ;
  443.             if(cnt-- == 0)
  444.                 break;
  445.             outportb(data,*cp++); /* Send the character */
  446.         }
  447.         write_scc(ctl,R0,RES_EOM_L);    /* Allow CRC generation */
  448.  
  449.         /* End of frame. Wait for TxEOM to go high, indicating start of
  450.          * CRC transmission. Note that we don't reset the transmit
  451.          * interrupt pending flag as one ordinarily would, since we're
  452.          * not using tx interrupts.
  453.          */
  454.         while(!(inportb(ctl) & TxEOM))
  455.             ;
  456.  
  457.         free(buffer);
  458.     }
  459. }
  460.  
  461. /* Turn on high speed transmitter. Does p-persistence, then sends a dummy
  462.  * frame to allow for keyup delay. Returns with transmitter on and interrupts
  463.  * disabled
  464.  */
  465. static void
  466. hstxon(hp)
  467. struct hdlc *hp;
  468. {
  469.     int16 ctl,data;
  470.     int i;
  471.  
  472.     ctl = hp->ctl;
  473.     data = hp->data;
  474.  
  475.     /* P-persistence. The slot time is fixed at one tick. */
  476.     while((rand() & 0xff) > uchar(hp->p))
  477.         pause(1L);
  478.  
  479.     /* Prevent distractions. In particular, block off the DCD interrupt
  480.      * so we don't hear our own carrier and hang in the interrupt handler!
  481.      * Note that simply disabling CPU interrupts isn't enough since
  482.      * the call to pause will block and the kernel will re-enable
  483.      * them.
  484.      */
  485.     write_scc(ctl,R9,0);    /* Disable all SCC interrupts */
  486.     (void)dirps();        /* Return value is always 1 */
  487.  
  488.     /* Turn on carrier, enable transmitter */
  489.     write_scc(ctl,R5,TxCRC_ENAB | RTS | TxENAB | Tx8 | DTR);
  490.  
  491.     /* Delay by sending dummy frame */
  492.     for(i=hp->txdelay;i != 0;i--){
  493.         while(!(inportb(ctl) & Tx_BUF_EMP))
  494.             ;
  495.         outportb(data,0);
  496.     }
  497.     write_scc(ctl,R0,RES_EOM_L);    /* Allow CRC generation */
  498.  
  499.     /* End of frame. Wait for TxEOM to go high, indicating start of
  500.      * CRC transmission. Note that we don't reset the transmit interrupt
  501.      * pending flag as one ordinarily would, since we're not using tx
  502.      * interrupts.
  503.      */
  504.     while(!(inportb(ctl) & TxEOM))
  505.         ;
  506. }
  507. /* Turn transmitter off at the end of a series of frames */
  508. static void
  509. hstxoff(hp)
  510. struct hdlc *hp;
  511. {
  512.     int cnt;
  513.     int16 ctl,data;
  514.  
  515.     ctl = hp->ctl;
  516.     data = hp->data;
  517.     /* To allow the SCC buffering to drain, we begin a dummy frame,
  518.      * then abort it
  519.      */
  520.     for(cnt=5;cnt != 0;cnt--){
  521.         while(!(inportb(ctl) & Tx_BUF_EMP))
  522.             ;
  523.         outportb(data,0);
  524.     }
  525.     write_scc(ctl,R0,SEND_ABORT);
  526.  
  527.     /* Turn off carrier and disable transmitter */
  528.     write_scc(ctl,R5,TxCRC_ENAB | Tx8 | DTR);
  529.     /* Re-Enable SCC interrupts */
  530.     write_scc(ctl,R9,MIE|NV);        
  531.     restore(1);    /* Turn interrupts back on */
  532. }
  533.  
  534. int
  535. dohs(argc,argv)
  536. int argc;
  537. char *argv[];
  538. {
  539.     register int i;
  540.     register struct hdlc *hp;
  541.  
  542.     for(i=0;i<2*Nhs;i++){
  543.         hp = &Hdlc[i];
  544.         printf("port %d: txpkts %lu ints %lu rxpkts %lu rxbytes %lu nomem %lu toobig %lu crcerr %lu aborts %lu overrun %lu\n",
  545.             i,hp->txpkts,hp->exints,hp->good,hp->rxbytes,
  546.             hp->nomem,hp->toobig,hp->crcerr,hp->aborts,hp->overrun);
  547.     }
  548.     return 0;
  549. }
  550. #ifdef    notdef        /* replaced with assembler in 8530.asm */
  551. /* Read data from the 8530 receiver.
  552.  * Returns when either a good frame is received, or when carrier drops.
  553.  * If a good frame is received, the length is returned; otherwise -1.
  554.  */
  555. int
  556. rx8530(ctl,data,buf,bufsize)
  557. int16 ctl,data;
  558. char *buf;
  559. int16 bufsize;
  560. {
  561.     int cnt = 0;
  562.     register char status;
  563.     char error;
  564.     register char *cp = buf;
  565.  
  566.     for(;;){
  567.         status = inportb(ctl);
  568.         if(!(status & DCD)){
  569.             cnt = -1;
  570.             break;
  571.         } else if(status & BRK_ABRT){
  572.             cp = buf;
  573.             cnt = 0;
  574.         } else if(status & Rx_CH_AV){
  575.             /* Receive character is ready, get it */
  576.             *cp++ = inportb(data);
  577.             if(++cnt > bufsize){
  578.                 /* Buffer overflow, start again */
  579.                 write_scc(ctl,R3,ENT_HM|RxENABLE|RxCRC_ENAB|Rx8);
  580.                 cp = buf;
  581.                 cnt = 0;
  582.             }
  583.         } else if((error = read_scc(ctl,R1)) & END_FR){
  584.             if(!(error & CRC_ERR))
  585.                 break;    /* Good frame! */
  586.             /* Bad frame, start again */
  587.             cp = buf;
  588.             cnt = 0;
  589.         }
  590.     }
  591.     return cnt;
  592. }
  593. #endif
  594.  
  595.